﻿using System;
using System.Threading;

namespace ClewareWrapper
{
    public class AdvancedTrafficLight : IDisposable
    {
        private const int MidTempo = 400;

        private SimpleTrafficLight _simpleTrafficLight;
        private bool _disposed;
        private Thread blinkingThread;
        private readonly BlinkingLight[] _lights;

        public AdvancedTrafficLight(Device device)
        {
            _simpleTrafficLight = new SimpleTrafficLight(device);
            _lights = new[]
                          {
                              new BlinkingLight(b => _simpleTrafficLight.Red = b),
                              new BlinkingLight(b => _simpleTrafficLight.Orange = b),
                              new BlinkingLight(b => _simpleTrafficLight.Green = b),
                          };
            blinkingThread = new Thread(() =>
                                        {
                                            while (true)
                                            {
                                                Thread.Sleep(MidTempo);
                                                foreach (var light in _lights)
                                                {
                                                    light.BlinkingTick();
                                                }
                                            }
                                        });
            blinkingThread.Start();
        }

        public AdvancedState Red
        {
            get { return _lights[0].State; }
            set { _lights[0].State = value; }
        }

        public AdvancedState Orange
        {
            get { return _lights[1].State; }
            set { _lights[1].State = value; }
        }

        public AdvancedState Green
        {
            get { return _lights[2].State; }
            set { _lights[2].State = value; }
        }

        public void SwitchOff()
        {
            foreach (var light in _lights)
            {
                light.State = AdvancedState.Off;
            }
        }

        public void SetRedOnly()
        {
            SetExclusiveSwitch(_lights[0], AdvancedState.On);
        }

        public void SetOrangeOnly()
        {
            SetExclusiveSwitch(_lights[1], AdvancedState.On);
        }

        public void SetGreenOnly()
        {
            SetExclusiveSwitch(_lights[2], AdvancedState.On);
        }

        public void BlinkRedOnly()
        {
            SetExclusiveSwitch(_lights[0], AdvancedState.Blinking);
        }

        public void BlinkOrangeOnly()
        {
            SetExclusiveSwitch(_lights[1], AdvancedState.Blinking);
        }

        public void BlinkGreenOnly()
        {
            SetExclusiveSwitch(_lights[2], AdvancedState.Blinking);
        }

        private void SetExclusiveSwitch(BlinkingLight lightOn, AdvancedState onState)
        {
            foreach (var light in _lights)
            {
                light.State = light == lightOn ? onState : AdvancedState.Off;
            }
        }

        public void SetFromColors(AdvancedColors colors)
        {
            var onState = colors.HasFlag(AdvancedColors.Blinking) ? AdvancedState.Blinking : AdvancedState.On;
            Red = colors.HasFlag(AdvancedColors.Red) ? onState : AdvancedState.Off;
            Orange = colors.HasFlag(AdvancedColors.Orange) ? onState : AdvancedState.Off;
            Green = colors.HasFlag(AdvancedColors.Green) ? onState : AdvancedState.Off;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this._disposed)
            {
                if (disposing)
                {
                    blinkingThread.Abort();
                }
                _disposed = true;
            }
        }
    }
}
